package com.stgy.lease.web.api.interceptor;

import com.stgy.lease.common.exception.StgyException;
import com.stgy.lease.common.result.ResultCodeEnum;
import com.stgy.lease.common.utils.JwtUtil;
import com.stgy.lease.model.domain.UserInfo;
import com.stgy.lease.web.api.vo.UserInfoVo;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.checkerframework.checker.units.qual.C;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.Map;

/**
 * ClassName:StgyAuthInterceptor
 * Package:com.stgy.lease.web.api.interceptor
 * Description:
 *
 * @Author:helei
 * @Create:2024/9/6 - 9:43
 */
@Component
public class StgyAuthInterceptor implements HandlerInterceptor {
    /*
        filter：对访问servlet的请求进行拦截过滤

        springmvc interceptor:对controller接口访问前后进行拦截
            对访问接口的方法进行拦截 进行登录校验
            在业务方法中可能需要使用token中的数据 或者基于token解析得到的用户信息(id...)
            可以方便使用容器中的其他对象 或者 透传数据(拦截器将解析的结果 传递给 接口方法)
            拦截器可以基于路径表达式 进行判断 是否要拦截请求
            使用场景：需要通过路径匹配拦截、透传数据

        aop对 方法进行增强 事务管理，前后日志输出，异常捕获 缓存管理
            判断用户是否登录：获取token 解析token(得到claims)...
            通过反射调用目标方法：aop不便于将解析token的结果传入
            使用场景：不需要透传数据、被增强的方法没有统一的特点
     */

    public static final ThreadLocal<UserInfo> THREAD_LOCAL = new ThreadLocal<>();

    //接口方法执行前调用
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //访问目标接口的方法，可以获取请求头中的token 解析判断用户登录状态是否有效
        String token = request.getHeader("access_token");
        if (StringUtils.isEmpty(token)) {
            throw new StgyException(ResultCodeEnum.APP_LOGIN_AUTH);
        }
        Map<String, Object> map = JwtUtil.parseToken(token, request);
        String avatar = map.get("avatar").toString();
        String name = map.get("name").toString();
        Long userId = Long.parseLong(map.get("userId").toString());
        //将map的数据 转为userInfo对象
        UserInfo userInfo = new UserInfo();
        userInfo.setId(userId);
        userInfo.setNickname(name);
        userInfo.setAvatarUrl(avatar);
        //线程共享数据
        THREAD_LOCAL.set(userInfo);
        //失效 拒绝访问
        //有效 放行 同时将token解析的结果缓存透传给后续的业务
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        THREAD_LOCAL.remove();
    }
}
